<?php 

namespace App\Services;

use Illuminate\Http\Request;
use Image;

// 上传管理
class UploadManager
{
	private $config;

    // 当前错误
    private $error = '';

    protected $path = 'data';

    // 允许上传的图片格式
    protected $imgExtAccepted = ['jpg', 'jpe', 'jpeg', 'png', 'gif'];

    // 允许上传的文件格式
    protected $extAccepted = ['jpg', 'jpe', 'jpeg', 'png', 'gif', 'zip', 'rar', 'doc', 'docx', 'ppt', 'psd', 'txt'];

    // 上传状态信息
    protected $stateInfo;

    // 文件相关信息
    protected $data;

    private $stateMap = [
        "SUCCESS", //上传成功标记，在UEditor中内不可改变，否则flash判断会出错
        "文件大小超出 upload_max_filesize 限制",
        "文件大小超出 MAX_FILE_SIZE 限制",
        "文件未被完整上传",
        "没有文件被上传",
        "上传文件为空",
        "ERROR_TMP_FILE" => "临时文件错误",
        "ERROR_TMP_FILE_NOT_FOUND" => "找不到临时文件",
        "ERROR_SIZE_EXCEED" => "文件大小超出网站限制",
        "ERROR_TYPE_NOT_ALLOWED" => "文件类型不允许",
        "ERROR_CREATE_DIR" => "目录创建失败",
        "ERROR_DIR_NOT_WRITEABLE" => "目录没有写权限",
        "ERROR_FILE_MOVE" => "文件保存时出错",
        "ERROR_FILE_NOT_FOUND" => "找不到上传文件",
        "ERROR_WRITE_CONTENT" => "写入文件内容错误",
        "ERROR_UNKNOWN" => "未知错误",
        "ERROR_DEAD_LINK" => "链接不可用",
        "ERROR_HTTP_LINK" => "链接不是http链接",
        "ERROR_HTTP_CONTENTTYPE" => "链接contentType不正确",
        "INVALID_URL" => "非法 URL",
        "INVALID_IP" => "非法 IP"
    ];

    public function __construct($config = array())
    {
    	if (!empty($config)) {
    		$this->config = $config;
    	}
    }

    public function upload(Request $request)
    {
       $this->putFile($request);

       return $this->getUploadFileInfo();
    }

    /**
     * 上传文件到服务器
     *
     * @param $upToken    上传凭证
     * @param $key        上传文件名
     * @param $data       上传二进制流
     * @param $mime       上传数据的mimeType
     * @param $checkCrc   是否校验crc32
     *
     * @return array    包含已上传文件的信息
     */
    public function putFile(Request $request, $name = 'file')
    {
		if ($request->hasFile($name)) {
		    $file = $request->file($name);
			if ($file->isValid()) {
				$this->extension = $file->getClientOriginalExtension();
        		$this->filesize  = $file->getSize();
        		$this->filename  = $this->makeFilename().'.'.$this->extension;
        		$this->directory = $this->path.'/'.$this->getDirectory();
                $this->pathname  = $this->getFullPath($this->directory);
                $this->mime      = $file->getMimeType();
                $this->relativePath = $this->getRelativePath();

                $this->allowType = ($request->input('type') == 1) ? $this->imgExtAccepted : $this->extAccepted;

                // 检查是否不允许的文件格式
                if (!$this->checkType()) {
                    $this->stateInfo = $this->getStateInfo("ERROR_TYPE_NOT_ALLOWED");
                    return;
                }

                //创建目录失败
                if (!file_exists($this->pathname) && !mkdir($this->pathname, 0777, true)) {
                    $this->stateInfo = $this->getStateInfo("ERROR_CREATE_DIR");
                    return;
                } else if (!is_writeable($this->pathname)) {
                    $this->stateInfo = $this->getStateInfo("ERROR_DIR_NOT_WRITEABLE");
                    return;
                }

                // 文件上传
                if ($file->isValid()) {
                    $file->move($this->pathname, $this->filename);   
                    $this->stateInfo = $this->stateMap[0];

                    // 创建缩略图
                    $this->thumb = '';
                    if ($request->input('thumb')) {
                        $thumbSize = $request->input('thumb');
                        list($width, $height) = explode('x', $thumbSize);
                        $this->thumb = $this->relativePath."_{$thumbSize}.jpg";
                        Image::make($this->relativePath)->fit($width, $height, null, 'top')->save($this->thumb, 100);
                    }
                    

                } else {
                    $this->stateInfo = $this->getStateInfo("ERROR_FILE_MOVE");
                }

                return $this;
			}
		}
    }

    // 百度编辑器处理文件上传
    public function ueditor(Request $request)
    {
        $action = $request->input('action');

        if ($action == 'config') {
            return $this->getUeditorConfig();
        }

        $this->ueditorUpload($request, $action);

        return $this->getUeditorFileInfo();
    }

    // 编辑器配置项
    private function getUeditorConfig()
    {
        return json_decode(preg_replace("/\/\*[\s\S]+?\*\//", "", file_get_contents("js/ueditor/config.json")), true);
    }

    // 编辑器文件上传
    private function ueditorUpload($request, $action)
    {
        $config = $this->getUeditorConfig();
        $this->allowType = ($action == 'image') ? $this->imgExtAccepted : $this->extAccepted;

        $fieldName = 'file';

        if ($request->hasFile($fieldName)) {
            $file = $request->file($fieldName);

            $this->extension    = $file->getClientOriginalExtension();
            $this->originalname = $file->getClientOriginalName();
            $this->filesize     = $file ->getClientSize();

            $this->directory = $this->path.'/'.$this->getDirectory();
            $this->pathname  = $this->getFullPath($this->directory);
            $this->filename  = $this->makeFilename().'.'.$this->extension;
            $this->fullname  = $this->getFullName();

            // 检查是否不允许的文件格式
            if (!$this->checkType()) {
                $this->stateInfo = $this->getStateInfo("ERROR_TYPE_NOT_ALLOWED");
                return;
            }

            //创建目录失败
            if (!file_exists($this->pathname) && !mkdir($this->pathname, 0777, true)) {
                $this->stateInfo = $this->getStateInfo("ERROR_CREATE_DIR");
                return;
            } else if (!is_writeable($this->pathname)) {
                $this->stateInfo = $this->getStateInfo("ERROR_DIR_NOT_WRITEABLE");
                return;
            }

            // 文件上传
            if ($file->isValid()) {
                $file->move($this->pathname, $this->filename);   
                $this->stateInfo = $this->stateMap[0];
            } else {
                $this->stateInfo = $this->getStateInfo("ERROR_FILE_MOVE");
            }
        }
    }

    // 生成新的文件名称
	protected function makeFilename()
	{
        return substr(md5(time().rand(1, 10000000000)), 0, 10).strtolower(str_random(6));
	}

    // 从给定的部分路径得到的完整的磁盘路径
    protected function getFullPath($path)
    {
        return public_path() . '/' .$path;
    }

    /**
     * 获取文件完整路径
     * @return string
     */
    private function getFullName()
    {
        return url($this->directory . $this->filename);
    }

    private function getRelativePath()
    {
        return $this->directory . $this->filename;
    }

    // 上传目录
    protected function getDirectory()
    {
    	return date('Y').'/'.date('m').'/';
    }

    /**
     * 文件类型检测
     * @return bool
     */
    private function checkType()
    {
        return in_array($this->extension, $this->allowType);
    }

     /**
     * 获取当前上传成功文件的各项信息 - 标准文件上传
     * @return array
     */
    public function getUploadFileInfo()
    {
        return [
            'state'       => $this->stateInfo,
            'path'        => $this->relativePath,
            'thumb'       => $this->thumb,
            'extension'   => $this->extension,
            'filesize'    => $this->filesize,
            'mime'        => $this->mime
        ];
    }  

    /**
     * 获取当前上传成功文件的各项信息 - 百度编辑器
     * @return array
     */
    public function getUeditorFileInfo()
    {
        return [
            "state"     => $this->stateInfo,
            "url"       => $this->fullname,
            "title"     => $this->originalname,
            "original"  => $this->originalname,
            "type"      => $this->extension,
            "size"      => $this->filesize
        ];
    }

    /**
     * 上传错误检查
     * @param $errCode
     * @return string
     */
    private function getStateInfo($errCode)
    {
        return !$this->stateMap[$errCode] ? $this->stateMap["ERROR_UNKNOWN"] : $this->stateMap[$errCode];
    }

    // 上传错误处理
    private function getErrorMessage($file)
    {
        static $errors = [
            UPLOAD_ERR_INI_SIZE   => '您上传文件过大',
            UPLOAD_ERR_FORM_SIZE  => '您上传文件过大',
            UPLOAD_ERR_PARTIAL    => '文件只有部分被上传',
            UPLOAD_ERR_NO_FILE    => '没有文件被上传',
            UPLOAD_ERR_CANT_WRITE => '文件无法写入磁盘',
            UPLOAD_ERR_NO_TMP_DIR => '临时目录丢失',
            UPLOAD_ERR_EXTENSION  => 'PHP扩展限制了上传',
        ];

        $errorCode = $file->getError();

        $maxFilesize = $errorCode === UPLOAD_ERR_INI_SIZE ? $file->getMaxFilesize() / 1024 : 0;
        $message = isset($errors[$errorCode]) ? $errors[$errorCode] : '文件 "%s" 上传失败.';

        return sprintf($message, $file->getClientOriginalName(), $maxFilesize);
    }

}